/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dgbgui.gui.shapes;



import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

public class LineWithArrowShape implements Shape {
    
    public LineWithArrowShape(Line2D line, double headLength, double headAngle) {
        m_line = line;
        m_headLength = headLength;
        m_headAngle = headAngle;
        
    }
    
    
    

    public PathIterator getPathIterator(AffineTransform transform) {
        //return m_bounding.getPathIterator(arg0);
        return new ArrowPathIterator(
                m_line.getP1(),
                m_line.getP2(),
                m_headLength,m_headAngle,
                transform);
                
    }

    public PathIterator getPathIterator(AffineTransform transform, double flatness) {
        //return m_bounding.getPathIterator(arg0,arg1);
        return new ArrowPathIterator(
                m_line.getP1(),
                m_line.getP2(),
                m_headLength,m_headAngle,
                transform);
        
    }

    
    public boolean contains(Point2D p) {
        return m_line.contains(p);
    }

    public boolean contains(Rectangle2D r) {
        return m_line.contains(r);
    }

    public boolean contains(double x, double y) {
        return m_line.contains(x,y);
    }

    public boolean contains(double x, double y, double w, double h) {
        return m_line.contains(x,y,w,h);
    }

    public Rectangle getBounds() {
        return m_line.getBounds();
    }

    public Rectangle2D getBounds2D() {
        return m_line.getBounds2D();
    }

    public boolean intersects(Rectangle2D r) {
        return m_line.intersects(r);
    }

    public boolean intersects(double x, double y, double w, double h) {
        return m_line.intersects(x,y,w,h);
    }
    
    private static class ArrowPathIterator implements PathIterator {
        
        public ArrowPathIterator(
                Point2D from,
                Point2D to,
                double headLength, double headAngle,
                AffineTransform trans) {
            
            m_trans = trans;

            double r = from.distance(to);
            double angle = Math.atan2(
                    to.getY() - from.getY(),
                    to.getX() - from.getX());
            
            
            
            double x1 = Math.cos(angle)*(r - headLength) - Math.sin(angle)*(headLength/3);
            double y1 = Math.sin(angle)*(r - headLength) + Math.cos(angle)*(headLength/3);
            
            double x2 = Math.cos(angle)*(r - headLength) - Math.sin(angle)*(-headLength/3);
            double y2 = Math.sin(angle)*(r - headLength) + Math.cos(angle)*(-headLength/3);;
            
            
            m_numValues = 10;
            m_geometry = new double[10];

            int pointIndex = 0;
            m_geometry[pointIndex++] = from.getX(); m_geometry[pointIndex++] = from.getY();
            m_geometry[pointIndex++] = to.getX(); m_geometry[pointIndex++] = to.getY();
            m_geometry[pointIndex++] = from.getX() + x1; m_geometry[pointIndex++] = from.getY() + y1;
            m_geometry[pointIndex++] = from.getX() + x2; m_geometry[pointIndex++] = from.getY() + y2;
            m_geometry[pointIndex++] = to.getX(); m_geometry[pointIndex++] = to.getY();
           
        }

        private Point2D.Double currentSegment() {
            Point2D.Double tempPoint = new Point2D.Double(
                    m_geometry[m_currentIndex*2],
                    m_geometry[m_currentIndex*2+1]);
            if (m_trans != null) {
                m_trans.transform(tempPoint, tempPoint);
            }
            return tempPoint;
        }
        
        public int currentSegment(float[] coords) {
            Point2D tempPoint = currentSegment();
            coords[0] = (float)tempPoint.getX();
            coords[1] = (float)tempPoint.getY();
            return (m_currentIndex == 0 ? PathIterator.SEG_MOVETO : PathIterator.SEG_LINETO);
        }

        public int currentSegment(double[] coords) {
            Point2D tempPoint = currentSegment();
            coords[0] = tempPoint.getX();
            coords[1] = tempPoint.getY();
            return (m_currentIndex == 0 ? PathIterator.SEG_MOVETO : PathIterator.SEG_LINETO);
        }

        public int getWindingRule() {
            return GeneralPath.WIND_EVEN_ODD;
        }

        public boolean isDone() {
            return m_currentIndex*2 == m_numValues;
        }

        public void next() {
            ++m_currentIndex;
            
        }
        
        int m_currentIndex = 0;
        int m_numValues = 0;
        double[] m_geometry;
        private AffineTransform m_trans;
    
    }
    
    Line2D m_line;
    double m_headLength;
    double m_headAngle;
    

}

